/*
 * Created on Mar 10, 2009
 */
package com.mgmaps.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Hashtable;
import com.mgmaps.tools.IOTools;
import com.mgmaps.tools.StringTools;

public class LS {
  
  private LS() {
  }
  
  private static String[] langNames;
  private static String[] langDescs;
  
  private static Hashtable strings;
  
  /**
   * Load the list of languages.
   */
  private static void loadLanguageList(InputStream is) {
    try {
      if (is == null)
        is = new LS().getClass().getResourceAsStream("/intl/languages.txt");
      Reader r = IOTools.openUTFReader(is);
      // read the number of languages
      int count = Integer.parseInt(IOTools.readLine(r));
      langNames = new String[count];
      langDescs = new String[count];
      // read the languages
      for (int i=0; i<count; i++) {
        String line = IOTools.readLine(r).trim();
        String[] splits = StringTools.split(line, ' ');
        if (splits.length < 1)
          throw new Exception("Invalid language specified: " + line);
        langNames[i] = splits[0];
        langDescs[i] = splits[1];
        for (int k=2; k<splits.length; k++)
          langDescs[i] += ' ' + splits[k];
      }
      r.close();
      is = null;
    }
    catch (Exception ex) {
      ExtLogger.handle(ex, false, "Error reading languages.txt");
      langNames = null;
      langDescs = null;
    }
    finally {
      // close the file
      if (is != null)
        try {
          is.close();
        }
        catch (IOException ie) {
        }
    }
  }
  
  /**
   * Get available languages.
   * @return array of strings (short names)
   */
  public static String[] getLangNames() {
    if (langNames == null)
      loadLanguageList(null);
    
    return langNames;
  }
  
  /**
   * Get available languages.
   * @return array of strings (long names)
   */
  public static String[] getLangDescs() {
    if (langDescs == null)
      loadLanguageList(null);
    
    return langDescs;
  }
  
  /**
   * Set the default language.
   * @throws NullPointerException if no language definition found
   */
  public static void setDefaultLanguage() {
    setLanguage(getLangNames()[0]);
  }
  
  /**
   * Set a language. Reads the language file.
   * @param lang language name
   */
  public static void setLanguage(String lang) {
    setLanguage(lang, null);
  }
  
  public static void setLanguage(int index) {
    setLanguage(langNames[index], null);
  }
  
  /**
   * Set a language. Reads the language file or an input stream.
   * @param lang language name
   * @param is input stream
   */
  public static void setLanguage(String lang, InputStream is) {
    // debugging
    ExtLogger.debug("Loading language " + lang);
    
    // open the file and read it
    try {
      if (is == null)
        is = new LS().getClass().getResourceAsStream("/intl/" + lang + ".lng");
      final Reader r = IOTools.openUTFReader(is);
      // read the messages
      if (strings != null)
        strings.clear();
      strings = new Hashtable();
      while(true) {
        String line = IOTools.readLine(r);
        if (line == null)
          break;
        
        line = line.trim();

        // comment or empty
        if (line.length() == 0 || line.charAt(0) == '#')
          continue;
        
        final int pos = line.indexOf('=');
        try {
          if (pos < 0)
            throw new Exception();
          else {
            final String key = line.substring(0, pos).trim();
            final String value = line.substring(pos+1).trim();
            if (strings.get(key) != null)
              ExtLogger.debug("Multiple language definitions for " + key);
            // replace "\n" strings with '\n' characters
            strings.put(key, StringTools.substituteAll(value, "\\n", "\n"));
          }
        }
        catch (Exception ex) {
          // we're here if either an invalid line was read (no =), or an invalid message number (can't parse)
          ExtLogger.debug("Invalid line in language file: " + line);
        }
      }
      r.close();
      is = null;
    }
    catch (Exception ex) {
      ExtLogger.handle(ex, false, "Message file for language " + lang + " could not be loaded");
      
      if (!lang.equals(langNames[0]))
        // language not found, load defaults
        setDefaultLanguage();
    }
    finally {
      // close the file
      if (is != null)
        try {
          is.close();
        }
        catch (IOException ie) {
        }
    }
  }
  
  /**
   * Get translation for a key.
   * @param key key name
   * @return translation
   */
  public static String get(String key) {
    final String value = (String) strings.get(key);
    if (value == null)
      return "{" + key + "}";
    else
      return value;
  }
  
  /**
   * Get translation for a key with arguments.
   * @param key key
   * @param args arguments
   * @return translation
   */
  public static String get(String key, String[] args) {
    String value = get(key);
    for (int i=0; i<args.length; i++)
      value = StringTools.substituteAll(value, "{" + (i+1) + "}", args[i]);
    return value;
  }

  /**
   * Get the index of a language.
   * @param language language name
   * @return index in the array, -1 if not found
   */
  public static int getLanguageIndex(String language) {
    for (int i=0; i<langNames.length; i++)
      if (langNames[i].equals(language))
        return i;
    return -1;
  }

}
